package gmodel

import (
	"database/sql/driver"
	"fmt"
	"github.com/andeya/ameda"
	"math"
	"strconv"
)

/*
Precision2

	两位小数类型，实现gorm的自定义数据类型，保存时精度限制为2位小数，用于金额，百分比等场景
	gorm声明支持：

		gorm:"type:decimal(11,2)
		"gorm:"precision:11,2"
*/
type Precision2 float64

// 实现 JSON 序列化接口
func (d Precision2) MarshalJSON() ([]byte, error) {
	return []byte(fmt.Sprintf("%.2f", d)), nil
}

// 实现 SQL 的扫描接口
func (d *Precision2) Scan(value interface{}) (err error) {
	floatV := float64(0)
	switch v := value.(type) {
	case float64: // 数据库返回的 float64
		floatV = v
	case []byte: // 数据库返回的十进制字符串
		floatV, err = strconv.ParseFloat(string(v), 64)
		if err != nil {
			return fmt.Errorf("invalid type for Amount: %v", err)
		}
	case string: // 数据库返回字符串
		floatV, err = strconv.ParseFloat(v, 64)
		if err != nil {
			return fmt.Errorf("invalid type for Amount: %v", err)
		}
	default: // 不支持的类型
		return fmt.Errorf("invalid type for Amount: %T", value)
	}
	*d = Precision2(math.Round(floatV*100) / 100)
	return nil
}

// 实现 SQL 的值接口
func (d Precision2) Value() (driver.Value, error) {
	return d.Float64(), nil
}

// 转float64保留2位小数,四舍五入,比较运算时用这个方法转成float64比较,避免浮点值问题
func (d Precision2) Float64() float64 {
	return math.Round(float64(d)*100) / 100
}

// 转整型分
//func (d *Precision2) Int64X100() (int64, error) {
//	return ameda.Float64ToInt64(d.Float64() * 100)
//}
//
//func (d *Precision2) Int64X100Must() int64 {
//	amt, err := ameda.Float64ToInt64(d.Float64() * 100)
//	if err != nil {
//		panic(err)
//	}
//	return amt
//}

// 转整型分
//func (d *Precision2) IntX100() (int, error) {
//	return ameda.Float64ToInt(d.Float64() * 100)
//}
//
//func (d *Precision2) IntX100Must() int {
//	amt, err := ameda.Float64ToInt(d.Float64() * 100)
//	if err != nil {
//		panic(err)
//	}
//	return amt
//}

func StringToPrecision2(v string) (p Precision2, err error) {
	fv, err := ameda.StringToFloat64(v)
	if err != nil {
		return 0, err
	}
	return Precision2(fv), nil
}

// 金额转成分
func Precision2ToIntX100[T int | int64](d Precision2) (T, error) {
	var zero T // 泛型零值
	floatValue := d.Float64() * 100

	// 根据目标类型进行转换
	switch any(zero).(type) {
	case int:
		intValue, err := strconv.Atoi(fmt.Sprintf("%.0f", floatValue))
		if err != nil {
			return zero, fmt.Errorf("failed to convert to int: %v", err)
		}
		return T(intValue), nil
	case int64:
		intValue, err := strconv.ParseInt(fmt.Sprintf("%.0f", floatValue), 10, 64)
		if err != nil {
			return zero, fmt.Errorf("failed to convert to int64: %v", err)
		}
		return T(intValue), nil
	default:
		return zero, fmt.Errorf("unsupported type: %T", zero)
	}
}

// 泛型函数：将 Precision2 转换为指定类型的整数值（单位：分），出错时 panic
func Precision2ToIntX100Must[T int | int64](d Precision2) T {
	value, err := Precision2ToIntX100[T](d)
	if err != nil {
		panic(err)
	}
	return value
}
